#!/usr/bin/env python
# encoding: utf-8
"""
@author: youfeng
@email: youfeng243@163.com
@license: Apache Licence
@file: asdl.py
@time: 2017/8/25 23:33
"""

import json
import random

import common
from config import ADSL_HOST_LIST, ADSL_TOKEN
from proxy_info import ProxyInfo


# 拨号类
class ADSLInfo(object):
    def __init__(self, log):
        self.log = log

        # 获得所有账号信息
        self.all_count_list = self.get_all_count_list()

        # 初始化获得所有代理信息
        self.proxy_list = self.get_all_proxy_list()

        # 站点计数器
        self.host_point_dict = {}

    # 初始化代理信息
    def init_proxy_info(self, index, host, username):
        self.log.info("进入线程任务: [host:{}] [username:{}]".format(host, username))
        return ProxyInfo(index, host, username, self.log)

    # 获得所有代理信息
    def get_all_proxy_list(self):

        self.log.info("开始第一次初始化所有代理信息...")

        # 多线程方式获取代理
        from multiprocessing.dummy import Pool as ThreadPool
        pool = ThreadPool(processes=10)

        result_list = list()
        index = 0
        for host, username in self.all_count_list:
            result_list.append(pool.apply_async(self.init_proxy_info, args=(index, host, username)))
            index += 1

        self.log.info("所有线程任务加载完成, 等待线程结束...")
        pool.close()
        pool.join()

        count = 0
        use_count = 0
        proxy_list = list()
        for result in result_list:
            proxy_info = result.get()
            proxy_list.append(proxy_info)
            self.log.info("当前代理信息: [序号:{}] [username:{}] [proxy:{}] [use_status:{}] [use_count:{}]".format(
                count, proxy_info.username, proxy_info.proxy,
                proxy_info.use_status, proxy_info.use_count))
            if proxy_info.use_status == ProxyInfo.USING:
                use_count += 1
            count += 1

        # 当有可用动态代理的时候才分配..
        if use_count > 0:
            self.re_alloc_point(proxy_list)
        else:
            raise Exception("异常: 没有一个可用代理....")

        self.log.info("代理信息初始化完成: size = {}".format(len(proxy_list)))
        return proxy_list

    # 重新分配可用代理指针...
    def re_alloc_point(self, proxy_list):

        # 重新分配可用指针..
        self.log.info("开始分配可用指针....")

        point = 0
        for index, item in enumerate(proxy_list):
            # 找出初始化失败的代理
            if item.use_status == ProxyInfo.USING:
                continue

            while True:
                if proxy_list[point].use_status == ProxyInfo.USING:
                    item.set_use_point(point)
                    point += 1
                    break
                point += 1
                if point >= len(proxy_list):
                    point = 0

            if point >= len(proxy_list):
                point = 0

        self.log.info("重新分配可用指针完成...")

    # 拨号获得所有的账号信息
    def get_all_count_list(self):

        all_count_list = []
        for host in ADSL_HOST_LIST:
            self.log.info("开始获取所有账户信息: {}".format(host))
            text = common.request_get("http://{}/un-list/?token={}".format(host, ADSL_TOKEN))

            try:
                if text is None:
                    self.log.error("当前账号获取代理信息失败: {}".format(host))
                    raise Exception("没有获得全部账号信息, 不启动....")

                result = json.loads(text)
                for username in result.get('usernames'):
                    self.log.info("当前获取到的账号信息为: {} {}".format(host, username))
                    all_count_list.append((host, username))
            except Exception as e:
                self.log.error("获取代理账号信息异常: ")
                self.log.exception(e)
                raise Exception("没有获得全部账号信息, 不启动....")

        self.log.info("当前总共代理账号数目: {}".format(len(all_count_list)))
        return all_count_list

    # 获取代理信息
    def get_proxy(self, host):
        # 获得当前指向的代理位置
        point = self.host_point_dict.get(host, None)
        if point is None:
            point = random.randint(0, len(self.proxy_list) - 1)

        # 防止指针越界
        if point < 0 or point >= len(self.proxy_list):
            point = 0

        # 获得代理信息
        proxy_info = self.proxy_list[point]

        # 更新指针位置
        self.host_point_dict[host] = point + 1

        # 如果当前代理可用 则直接提取代理
        if proxy_info.is_using():
            # 获得代理信息
            proxy = proxy_info.get_proxy()
        else:
            # 获取可用的代理
            proxy = self.proxy_list[proxy_info.get_use_point()].get_proxy()

            # 更新自己的代理
            proxy_info.update_proxy()

        return proxy
